package main

import (
	"bytes"
	"context"
	"crypto/aes"
	"crypto/cipher"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	tools "go-lang-tools"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"syscall"
	"time"

	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"unsafe"

	"github.com/PuerkitoBio/goquery"
	"github.com/axgle/mahonia"
	"github.com/chromedp/chromedp"
	"github.com/shopspring/decimal"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"

	"github.com/go-echarts/go-echarts/v2/charts"
	"github.com/go-echarts/go-echarts/v2/components"
	"github.com/go-echarts/go-echarts/v2/opts"
	_ "github.com/mattn/go-sqlite3"
	"github.com/xuri/excelize/v2"
	_ "golang.org/x/text/encoding/simplifiedchinese"
	_ "golang.org/x/text/transform"
)

var db *sql.DB
var err error
var currentDate string

func init() {
	tools.Logger = tools.WriteLogFile("demo", "")
	currentDate, _ = tools.GetCurrentStringDateFormat("2006-01-02")

	db, err = tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)

	if err != nil {
		tools.OutPutInfo(err, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}
}

func main() {
	//main19
	//var cookieStr string
	//for _, v := range get_cookies_from_chrome(".pinduoduo.com") {
	//	fmt.Println(v)
	//	cookieStr += v["name"] + "=" + v["value"] + ";"
	//}
	//tools.OutPutInfo(nil, "cookieStr:", cookieStr)
	//
	//resp, err := tools.SendRequstAutoCharsetWithHeaderMethod2(
	//	`https://kuajing.pinduoduo.com/oms/bg/venom/api/supplier/purchase/manager/querySubOrderList`,
	//	nil,
	//	map[string]string{
	//		"Content-Type": "application/json",
	//		"cookie":       cookieStr,
	//		"mallid":       "127537530351",
	//	},
	//	5000,
	//	"post",
	//	`{"pageNo":1,"pageSize":100,"urgencyType":0,"isCustomGoods":false,"statusList":[1]}`,
	//)
	//if err != nil {
	//	tools.OutPutInfo(err)
	//} else {
	//	tools.OutPutInfo(nil, "resp:", resp)
	//}
	//
	//file, err := tools.SendRequstWithHeaderSaveImage(
	//	`https://img.kwcdn.com/product/open/2022-11-10/1668068907604-83c7a14de6f44f9ea0327b100dfc7731-goods.jpeg`,
	//	nil, 5000, `./shangpin`, 90,
	//)
	//if err != nil {
	//	tools.OutPutInfo(err)
	//}
	//
	//err = tools.ZoomImg(file, file, 50, 0)
	//if err != nil {
	//	tools.OutPutInfo(err)
	//}

	f, err := excelize.NewFile("Book1.xlsx")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()
	// Create a new sheet.
	//index, err := f.NewSheet("Sheet2")
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}
	// Set value of a cell.
	//f.SetCellValue("Sheet2", "A2", "Hello world.")
	//f.SetCellValue("Sheet1", "B2", 100)

	if err := f.AddPicture("Sheet1", "E5", "shangpin.jpg", nil); err != nil {
		fmt.Println(err)
		return
	}

	// Set active sheet of the workbook.
	//f.SetActiveSheet(index)
	// Save spreadsheet by the given path.
	if err := f.Save(); err != nil {
		fmt.Println(err)
	}
}

// 转债涨跌幅为空，数据补全，通过当前收盘价和前收盘价计算出涨跌幅
func main18() {
	//main18
	defer db.Close()

	//1 查询所有bond
	b, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME like "bond\_%" 
and TABLE_NAME NOT LIKE "bond_template%" 
and TABLE_NAME != "bond_000000"
order by TABLE_NAME`, 3)
	if err != nil {
		tools.OutPutInfo(err, "查找数据库全部stock_*表列表[程序异常]")
		return
	}
	tools.OutPutInfo(nil, "b:", b)

	//2 循环bond code
	for _, v := range b {
		//2.1 查数据库是否存在涨跌幅为空的情况 select count(*) from bond_* where zhangdiefu is null
		sql := `select date,shoupan from ` + v["TABLE_NAME"] + `
where (zhangdiefu is null or zhangdiefu = "")
and shoupan is not null
and shoupan != ""
and shoupan != "-"
and kaipan is not null
and kaipan != ""
and kaipan != "-"
order by date asc
`
		data, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
			sql, 3)
		if err != nil {
			tools.OutPutInfo(err)
			return
		}
		tools.OutPutInfo(nil, "data:", data)

		//2.1.1 为空跳过
		if len(data) == 0 {
			continue
		}

		//2.1.2 循环每个日期 计算每天的上跌幅，四舍五入，存入数据库
		for kk, vv := range data {
			var zhangdiefu decimal.Decimal
			if kk == 0 {
				sql0 := `select date,shoupan from ` + v["TABLE_NAME"] + ` where date < '` + vv["date"] + `' limit 1`
				data0, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
					sql0, 3)
				if err != nil {
					tools.OutPutInfo(err)
					return
				}
				tools.OutPutInfo(nil, "data0:", data0)

				if len(data0) == 0 {
					continue
				}
				if data0[0]["shoupan"] == "" {
					continue
				}

				pre, err := decimal.NewFromString(data0[0]["shoupan"])
				if err != nil {
					tools.OutPutInfo(err)
					return
				}
				curr, err := decimal.NewFromString(vv["shoupan"])
				if err != nil {
					tools.OutPutInfo(err)
					return
				}
				zhangdiefu = curr.DivRound(pre, 4).Sub(decimal.NewFromInt(1)).Mul(decimal.NewFromInt(100))
				tools.OutPutInfo(nil, v["TABLE_NAME"], vv["date"], vv["shoupan"], zhangdiefu.String())
			} else {
				pre, err := decimal.NewFromString(data[kk-1]["shoupan"])
				if err != nil {
					tools.OutPutInfo(err)
					return
				}
				curr, err := decimal.NewFromString(vv["shoupan"])
				if err != nil {
					tools.OutPutInfo(err)
					return
				}
				zhangdiefu = curr.DivRound(pre, 4).Sub(decimal.NewFromInt(1)).Mul(decimal.NewFromInt(100))
				tools.OutPutInfo(nil, v["TABLE_NAME"], vv["date"], vv["shoupan"], zhangdiefu.String())
			}

			//更新数据库
			cnt, err := tools.UpdateTable(db, v["TABLE_NAME"], map[string]string{
				"date": vv["date"],
			}, map[string]string{
				"zhangdiefu": zhangdiefu.String(),
			})
			if err != nil {
				tools.OutPutInfo(err)
				return
			}
			tools.OutPutInfo(nil, "update", v["TABLE_NAME"], vv["date"], zhangdiefu.String(), "cnt:", cnt)
		}
	}
}

type DataDec struct {
	date              string
	zuigao            decimal.Decimal
	shoupan           decimal.Decimal
	chengjiaoliang    decimal.Decimal
	avgChengjiaoliang decimal.Decimal
	code              string
	name              string
	k                 int
}

func getStockTableList(db *sql.DB) ([]string, error) {
	b, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME like "stock\_%" 
and TABLE_NAME NOT LIKE "stock_8%" 
and TABLE_NAME NOT LIKE "stock_4%"
order by TABLE_NAME`, 3)
	if err != nil {
		tools.OutPutInfo(err, "查找数据库全部stock_*表列表[程序异常]")
		return nil, errors.New("查找数据库全部stock_*表列表[程序异常]" + err.Error())
	}
	var sliceCodes []string
	for _, v := range b {
		sliceCodes = append(sliceCodes, strings.ReplaceAll(v["TABLE_NAME"], "stock_", ""))
	}
	if detailLogFlag {
		tools.OutPutInfo(nil, "sliceCodes:", sliceCodes)
	}

	return sliceCodes, nil
}

//新高战法
/*
规则：
1.当前收盘价高于前一个高点A
2.找到高点A的前一个高点，且高于当前最高价的那一个高点，就是高点B
3.计算高点B与当前最高价的差幅（涨跌幅）
4.即将差幅排序
*/

func main17() {
	//main17
	//currentDate = "2023-03-02"
	stocks, err := getStockTableList(db)
	if err != nil {
		tools.OutPutInfo(err)
		return
	}

	titleGbk, err := tools.Utf8ToGbk("代码名称,当前日期,当前收盘价,当前最高价,高点A日期,高点A最高价,高点B日期,高点B最高价,距高点B涨跌幅%,高点A至当前平均成交量,当前成交量,高点A~B天数,当前涨跌幅,次日涨跌幅%,雪球链接\n")
	if err != nil {
		tools.OutPutInfo(err)
		return
	}
	tools.WriteLog(titleGbk, "./新高战法"+currentDate+".csv")
loop:
	for _, s := range stocks {
		tools.OutPutInfo2(nil, "p", "s:", s)
		sql := `
select * from stock_` + s + ` where date <= '` + currentDate + `' order by date desc limit 1000
`
		data, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "", sql, 3)
		if err != nil {
			tools.OutPutInfo(err)
			return
		}
		if detailLogFlag {
			tools.OutPutInfo(nil, "data:", data)
		}
		if len(data) == 0 {
			if detailLogFlag {
				tools.OutPutInfo(nil, s, "数据为空")
			}
			continue
		}

		if strings.Contains(data[0]["name"], "ST") {
			if detailLogFlag {
				tools.OutPutInfo(nil, data[0]["code"], data[0]["name"], data[0]["date"], "ST股,跳过")
			}
			continue
		}

		if data[0]["date"] != currentDate {
			if detailLogFlag {
				tools.OutPutInfo(nil, data[0]["code"], data[0]["name"], data[0]["date"], "第一条数据不是当天,跳过")
			}
			continue
		}

		var dataDecSlice []DataDec
		decZhangdiefu, err := decimal.NewFromString(data[0]["zhangdiefu"])
		if err != nil {
			tools.OutPutInfo(err)
			return
		}
		if decZhangdiefu.LessThan(decimal.Zero) {
			if detailLogFlag {
				tools.OutPutInfo(nil, data[0]["code"], data[0]["name"], data[0]["date"], "涨跌幅小于0", decZhangdiefu.String())
			}
			continue
		}

		decChengjiaoe, err := decimal.NewFromString(data[0]["chengjiaoe"])
		if err != nil {
			tools.OutPutInfo(err)
			return
		}
		if decChengjiaoe.LessThan(decimal.NewFromInt(100000000)) {
			if detailLogFlag {
				tools.OutPutInfo(nil, data[0]["code"], data[0]["name"], data[0]["date"], "成交额小于1亿", decZhangdiefu.String())
			}
			continue
		}

		for _, v := range data {
			if strings.Contains(v["name"], "退") ||
				strings.Contains(v["name"], "PT") ||
				strings.Contains(v["name"], "ST") {
				continue loop
			}
			decZuigao, err := decimal.NewFromString(v["zuigao"])
			if err != nil {
				tools.OutPutInfo(err)
				return
			}
			decShoupan, err := decimal.NewFromString(v["shoupan"])
			if err != nil {
				tools.OutPutInfo(err)
				return
			}
			decChengjiaoliang, err := decimal.NewFromString(v["chengjiaoliang"])
			if err != nil {
				tools.OutPutInfo(err)
				return
			}

			dataDecSlice = append(dataDecSlice, DataDec{
				date:           v["date"],
				zuigao:         decZuigao,
				shoupan:        decShoupan,
				chengjiaoliang: decChengjiaoliang,
				code:           v["code"],
				name:           v["name"]})
		}

		greatA := DataDec{date: "", zuigao: decimal.Zero}

		Ok := false
		var sumChengjiaoliang decimal.Decimal
		for k, v := range dataDecSlice {
			sumChengjiaoliang = sumChengjiaoliang.Add(v.chengjiaoliang)
			if k == 0 || k == len(dataDecSlice)-1 {
				if detailLogFlag {
					tools.OutPutInfo(nil, v.code, v.name, v.date, v.zuigao, "第一天或者最后一天")
				}
				continue
			}

			//找距离当前最近的一个高点
			if v.zuigao.GreaterThan(dataDecSlice[k-1].zuigao) && v.zuigao.GreaterThanOrEqual(dataDecSlice[k+1].zuigao) {
				if detailLogFlag {
					tools.OutPutInfo(nil, v.code, v.name, "高点", v.date, v.zuigao)
				}

				//判断当前收盘价是否高于这个高点，不高于就直接跳到下一个标的
				if dataDecSlice[0].zuigao.GreaterThan(v.zuigao) {
					//找到了高点A
					if greatA.zuigao.Equal(decimal.Zero) {
						avg := sumChengjiaoliang.DivRound(decimal.NewFromInt(int64(k+1)), 2)
						greatA = DataDec{date: v.date, zuigao: v.zuigao, avgChengjiaoliang: avg, k: k}
						if detailLogFlag {
							tools.OutPutInfo(nil, v.code, v.name, "高点A", greatA.date, greatA.zuigao, avg)
						}
					}
					Ok = true //这是一个有效的标的
					if detailLogFlag {
						tools.OutPutInfo(nil, v.code, v.name, "高点", v.date, v.zuigao, "当天收盘价大于高点,继续查找高点", dataDecSlice[0].shoupan)
					}
					continue
				} else {
					if Ok {
						if v.zuigao.GreaterThanOrEqual(dataDecSlice[0].zuigao) {
							//找到了高点B
							if detailLogFlag {
								tools.OutPutInfo(nil, v.code, v.name, "高点B", greatA.date, greatA.zuigao)
							}
							//计算当日收盘/高点b-1 *100
							zhangDieFu := dataDecSlice[0].shoupan.DivRound(v.zuigao, 4).Sub(decimal.NewFromInt(1)).Mul(decimal.NewFromInt(100))
							if detailLogFlag {
								tools.OutPutInfo(nil, "高点A", greatA.date, greatA.zuigao, "高点B", v.date, v.zuigao, "涨跌幅", zhangDieFu)
							}

							preCode := ""
							if v.code[:1] == "6" {
								preCode = "SH"
							} else {
								preCode = "SZ"
							}
							xueqiuUrl := `https://xueqiu.com/S/` + preCode + v.code

							//查询次日涨跌幅
							sqlnextDay := `
select zhangdiefu from stock_` + s + ` where date > '` + data[0]["date"] + `' order by date asc limit 1
`
							nextDay, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "", sqlnextDay, 3)
							if err != nil {
								tools.OutPutInfo(err, "sqlnextDay:", sqlnextDay)
								return
							}
							var nexeZhangdiefuTmp string
							if len(nextDay) == 0 {
								nexeZhangdiefuTmp = "-"
							}

							gbkData, err := tools.Utf8ToGbk(strings.Join([]string{
								v.code + v.name,
								dataDecSlice[0].date,
								dataDecSlice[0].shoupan.String(),
								dataDecSlice[0].zuigao.String(),
								greatA.date, greatA.zuigao.String(),
								v.date, v.zuigao.String(),
								zhangDieFu.String(),
								greatA.avgChengjiaoliang.String(),
								dataDecSlice[0].chengjiaoliang.String(), //当前成交量
								strconv.Itoa(k - greatA.k),              //高点A~B天数
								decZhangdiefu.String(),                  //当前涨跌幅
								nexeZhangdiefuTmp,
								xueqiuUrl,
							}, ",") + "\n")
							if err != nil {
								tools.OutPutInfo(err)
								return
							}
							tools.WriteLog(gbkData, "./新高战法"+currentDate+".csv")
							break
						} else {
							if detailLogFlag {
								tools.OutPutInfo(nil, v.code, v.name, v.date, v.zuigao, "没有比当前价高")
							}
						}
					} else {
						if detailLogFlag {
							tools.OutPutInfo(nil, v.code, v.name, v.date, v.zuigao, "当前价小于等于高点A的最高价，跳过该标的")
						}
						break
					}
				}
			} else {
				if detailLogFlag {
					tools.OutPutInfo(nil, v.code, v.name, v.date, v.zuigao, "不是高点")
				}
			}
		}
	}

	//tools.OutPutInfo(nil, "dataDecSlice:", dataDecSlice)

}

// 爬集思录待发转债、证监会核准后的标的，通过浏览器打开雪球k线图页面
func main15() {
	tools.Logger = tools.WriteLogFile("demo15", "")

	//调用接口
	url := `https://www.jisilu.cn/data/cbnew/pre_list/?___jsl=LST___t=1677158241752`
	resp, err := tools.SendRequstAutoCharsetWithHeaderMethod2(url, map[string]string{
		"cb_type_Y": "Y",
		"progress":  "90",
		"rp":        "22",
	}, map[string]string{
		"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
	}, 3000, "post", "")
	if err != nil {
		tools.OutPutInfo(err)
		fmt.Scanln()
		return
	}
	tools.OutPutInfo(nil, "resp:", resp)

	//解析数据
	dataMap, err := tools.JsonToMap(resp)
	if err != nil {
		tools.OutPutInfo(err)
		fmt.Scanln()
		return
	}
	tools.OutPutInfo(nil, "dataMap:", dataMap)

	rows, ok := dataMap["rows"]
	if !ok || rows == nil {
		tools.OutPutInfo(nil, "dataMap[rows]不存在")
		fmt.Scanln()
		return
	}

	rowsSlice := rows.([]interface{})
	if len(rowsSlice) == 0 {
		tools.OutPutInfo(nil, "没有证监会核准的转债")
		fmt.Scanln()
		return
	}

	tools.OutPutInfo(nil, len(rowsSlice))

	var xueQiuUrl []string
	for _, v := range rowsSlice {
		code := v.(map[string]interface{})["id"].(string)
		preCode := ""
		if code[:1] == "6" {
			preCode = "SH"
		} else {
			preCode = "SZ"
		}
		xueQiuUrl = append(xueQiuUrl, `https://xueqiu.com/S/`+preCode+code)

	}
	tools.OutPutInfo(nil, "xueQiuUrl:", xueQiuUrl)

	OpenBrowser(xueQiuUrl)

	//循环数据

	//打开浏览器
}

// 检查stock_*数据是否存在开收高低价格为-的情况
func main14() {
	tools.Logger = tools.WriteLogFile("demo", "")

	db, err1 := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	defer db.Close()
	if err1 != nil {
		tools.OutPutInfo(err1, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}

	stocks, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`SELECT TABLE_NAME FROM information_schema.TABLES 
WHERE TABLE_NAME like "stock\_%" AND TABLE_NAME <>"stock_template" order by TABLE_NAME`, 3)
	if err != nil {
		tools.OutPutInfo(err, "查找数据库全部etf表列表[程序异常]")
		panic(1)
	}
	tools.OutPutInfo(nil, "stocks:", stocks)

	//stocks = []map[string]string{
	//	{"TABLE_NAME":"stock_601633"},
	//}

	for _, stock := range stocks {
		//		a, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "", `
		//		select count(*) as cnt from `+stock["TABLE_NAME"]+` where kaipan = '-' and shoupan = '-'
		//`, 3)
		//		if err != nil {
		//			tools.OutPutInfo(err)
		//			return
		//		}
		//		if a[0]["cnt"] != "0" {
		//			tools.OutPutInfo(nil, stock["TABLE_NAME"])
		//			return
		//		}
		_, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "", `
		delete from `+stock["TABLE_NAME"]+` where kaipan = '-' and shoupan = '-' and zuigao = '-' and zuidi = '-'
		`, 3)
		if err != nil {
			tools.OutPutInfo(err)
			return
		} else {
			tools.OutPutInfo(nil, stock["TABLE_NAME"])
		}
		//调用东财接口获取股票价格数据

	}

}

// 获取全部stock数据的代码，废弃。
func main10() {
	tools.Logger = tools.WriteLogFile("demo", "")

	db, err1 := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	defer db.Close()
	if err1 != nil {
		tools.OutPutInfo(err1, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}

	stocks, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`SELECT TABLE_NAME FROM information_schema.TABLES 
WHERE TABLE_NAME like "stock\_%" AND TABLE_NAME <>"stock_template" order by TABLE_NAME`, 3)
	if err != nil {
		tools.OutPutInfo(err, "查找数据库全部etf表列表[程序异常]")
		panic(1)
	}
	tools.OutPutInfo(nil, "stocks:", stocks)

	//stocks = []map[string]string{
	//	{"TABLE_NAME":"stock_601633"},
	//}

	for _, stock := range stocks {
		code := strings.ReplaceAll(stock["TABLE_NAME"], "stock_", "")
		var codePre string
		if code[:1] == "6" {
			codePre = "1."
		} else {
			codePre = "0."
		}
		//调用东财接口获取股票价格数据
		url := `https://push2his.eastmoney.com/api/qt/stock/kline/get?secid=` + codePre + code + `&klt=101&fqt=1&lmt=5000&end=30220110&iscca=1&fields1=f1,f2,f3,f4,f5&fields2=f51,f52,f53,f54,f55,f56,f57,f59`
		resp, err := tools.SendRequstAutoCharsetWithHeaderMethod2(url, nil, nil, 3000, "get", "")
		if err != nil {
			tools.OutPutInfo2(err, "", "调用东财接口获取当天全部etf数据[异常]")
			return
		}
		if resp == "" {
			tools.OutPutInfo2(nil, "", "调用东财接口获取当天全部etf数据响应信息为空[异常]")
			return
		}
		if detailLogFlag {
			tools.OutPutInfo2(nil, "", "GetETFListAndInsert resp:", resp)
		}
		//解析json
		mapData, err := tools.JsonToMap(resp)
		if err != nil {
			tools.OutPutInfo2(err, "", "调用东财接口获取当天全部etf数据解析json[异常]")
			return
		}
		if len(mapData) == 0 {
			tools.OutPutInfo2(err, "", "调用东财接口获取当天全部etf数据解析后为空[异常]")
			return
		}
		if detailLogFlag {
			tools.OutPutInfo2(nil, "", "GetETFListAndInsert mapData:", mapData)
		}
		//total := mapData["data"].(map[string]interface{})["total"].(int)
		data, ok := mapData["data"]
		if !ok {
			tools.OutPutInfo2(err, "", "调用东财接口获取当天全部etf数据解析后为空[异常]")
			return
		}
		if data == nil {
			tools.OutPutInfo2(err, "", "调用东财接口获取当天全部etf数据解析后为空[异常]")
			continue
		}
		_, ok = mapData["data"].(map[string]interface{})["klines"]
		if !ok {
			tools.OutPutInfo2(err, "", "调用东财接口获取当天全部etf数据解析后为空[异常]")
			return
		}
		klines := mapData["data"].(map[string]interface{})["klines"].([]interface{})
		var insertData []map[string]string
		for _, kline := range klines {
			dSlice := strings.Split(kline.(string), ",")
			insertData = append(insertData, map[string]string{
				"code":           data.(map[string]interface{})["code"].(string),
				"name":           data.(map[string]interface{})["name"].(string),
				"date":           dSlice[0],                                //日期
				"kaipan":         dSlice[1],                                //开盘价
				"shoupan":        dSlice[2],                                //收盘价
				"zuigao":         dSlice[3],                                //最高价
				"zuidi":          dSlice[4],                                //最低价
				"chengjiaoliang": dSlice[5] + "00",                         //成交量
				"chengjiaoe":     strings.ReplaceAll(dSlice[6], ".00", ""), //成交额
			})
		}
		//tools.OutPutInfo(nil,"insertData:",insertData)
		cnt, err, _ := tools.InsertAllOneConnect(db, stock["TABLE_NAME"], insertData, "REPLACE")
		if err != nil {
			tools.OutPutInfo(err)
			return

		}
		tools.OutPutInfo(nil, stock["TABLE_NAME"], "插入成功cnt:", cnt)
	}

}

func main1() {
	tools.Logger = tools.WriteLogFile("./cb", "")

	//ddDll, err := syscall.LoadLibrary("DD94687.64.dll")
	//if err!=nil {
	//	tools.OutPutInfo(err)
	//	return
	//}
	//defer syscall.FreeLibrary(ddDll)// 严格来说需要加上
	//
	//ddDll.DD_mov(10, 10)

	//dd, err := syscall.LoadLibrary("DD94687.64.dll")
	//if err!=nil {
	//	tools.OutPutInfo(err)
	//	return
	//}
	////获取动态库中函数地址
	//mov, err := syscall.GetProcAddress(dd, "DD_mov")
	//if err!=nil {
	//	tools.OutPutInfo(err)
	//	return
	//}
	////调用函数，4为参数个数
	//_, _, err = syscall.Syscall9(mov,
	//	2,
	//	10,
	//	10,
	//	0,
	//	0,
	//	0,
	//	0,
	//	0,
	//	0,
	//	0)
	//
	//if err!=nil{
	//	tools.OutPutInfo(err)
	//	return
	//}
	////释放内存
	//defer syscall.FreeLibrary(dd)
	//GoCallDll1(4)
	//GoCallDll1(8)
	//GoCallDll1(100,10)
}
func GoCallDll2(a, b int) error {
	dd, _ := syscall.LoadLibrary("DD94687.64.dll")
	defer syscall.FreeLibrary(dd)
	mov, err := syscall.GetProcAddress(dd, "DD_key")
	if err != nil {
		tools.OutPutInfo(err)
		return err
	}
	fmt.Println("111", mov)

	_, _, err = syscall.Syscall(mov,
		2,
		uintptr(a),
		uintptr(b),
		0)
	if err != nil {
		tools.OutPutInfo(err)
		return err
	}
	return nil
}

func GoCallDll1(a int) uintptr {
	dllFile := syscall.NewLazyDLL("DD94687.64.dll")
	fmt.Println("dll:", dllFile.Name)
	key := dllFile.NewProc("DD_btn")
	fmt.Println("+++++++NewProc:", key, "+++++++")

	ret, _, err := key.Call(uintptr(a))
	if err != nil {
		tools.OutPutInfo(err)

	}
	//if err != nil && IsFinishError(err) {
	//	fmt.Println(dllFileName+fmt.Sprintf(":%d+%d", a, b)+"运算结果为:", ret)
	//} else {
	//	fmt.Println(fmt.Sprintf("%+v", err))
	//}
	return ret
}

func abort(funcname string, err error) {
	panic(fmt.Sprintf("%s failed: %v", funcname, err))
}

//var (
//	user32, _     = syscall.LoadLibrary("DD94687.64.dll")
//	messageBox, _ = syscall.GetProcAddress(user32, "DD_mov")
//)

func MessageBox(caption, text string) (result int) {
	//var nargs uintptr = 2
	//ret, _, callErr := syscall.Syscall9(messageBox,
	//	nargs,
	//	100,
	//	100,
	//	0,
	//	0,
	//	0,
	//	0,
	//	0,
	//	0,
	//	0)
	//if callErr != 0 {
	//	abort("Call MessageBox", callErr)
	//}
	//result = int(ret)
	return
}

func main2() {
	//defer syscall.FreeLibrary(user32)

	//fmt.Printf("Return: %d\n", MessageBox("Done Title", "This test is Done."))
	//fmt.Scanln()
}

var ld *syscall.LazyDLL

func main3() {
	//ld = syscall.NewLazyDLL("DD94687.64.dll")
	////ld = syscall.NewLazyDLL("DDHID64.dll")
	//keyMap := map[string]uintptr{
	//	"5": 205, "c": 503, "n": 506, "z": 501, "3": 203, "1": 201, "d": 403, "0": 210, "l": 409, "8": 208, "w": 302,
	//	"u": 307, "4": 204, "e": 303, "[": 311, "f": 404, "y": 306, "x": 502, "g": 405, "v": 504, "r": 304, "i": 308,
	//	"a": 401, "m": 507, "h": 406, ".": 509, ",": 508, "]": 312, "/": 510, "6": 206, "2": 202, "b": 505, "k": 408,
	//	"7": 207, "q": 301, "\"": 411, "\\": 313, "j": 407, "`": 200, "9": 209, "p": 310, "o": 309, "t": 305, "-": 211,
	//	"=": 212, "s": 402, ";": 410,
	//}
	//time.Sleep(time.Millisecond * 2000)
	//downUp(keyMap, "d")
	//downUp(keyMap, "e")
	//downUp(keyMap, "m")
	//downUp(keyMap, "o")
	//fmt.Println("1123")
	//fmt.Scanln()
}

func downUp(keyMap map[string]uintptr, key string) {

	action := ld.NewProc("DD_key")
	vkCode := keyMap[key]
	action.Call(vkCode, 1)
	time.Sleep(time.Millisecond * 200)
	action.Call(vkCode, 2)

}

func main4() {
	tools.Logger = tools.WriteLogFile("log", "")
	//a,b,_:=tools.CmdAndChangeDir("./",`C:\Users\Admin\Desktop\dist\a.exe`)
	//tools.OutPutInfo(nil,a)
	//tools.OutPutInfo(nil,b)

	//for i:=100;i<=999 ;i++  {
	//	if (i % 3 == 0) && (i%11==0) && ((i-1)%2==0)&& (i-1)%7==0{
	//		tools.OutPutInfo(nil,"i:",i)
	//	}
	//}
	list := []string{"4970.013", "5013.522", "4991.660", "4917.162", "4867.319", "4807.698", "4855.940", "4821.768", "4853.196", "4849.428", "4877.370", "4883.828", "4833.928", "4866.383", "4929.941", "4936.192", "4883.837", "4940.109", "4913.612", "4932.108", "4874.775", "4922.723", "4910.185", "4928.016", "4959.725", "4979.524", "4963.098", "4898.164", "4864.138", "4908.770", "4890.685", "4839.846", "4821.112", "4868.742", "4842.346", "4848.180", "4846.744", "4821.193", "4898.653", "4888.375", "4882.378", "4883.321", "4885.754", "4837.619", "4890.058", "4912.399", "4913.346", "4916.658", "4896.442", "4860.127", "4851.423", "4832.026", "4843.851", "4856.163", "4901.018", "4892.621", "4922.102", "4995.930", "5078.690", "5055.117", "5083.801", "5049.695", "5005.899", "5034.732", "4954.760", "4880.418", "4913.485", "4914.454", "4948.739", "4921.345", "4919.324", "4955.964", "4883.480", "4921.511", "4940.373", "4917.765", "4868.120", "4818.232", "4822.369", "4844.045", "4797.774", "4845.579", "4765.919", "4726.732", "4767.276", "4813.347", "4780.378", "4823.509", "4779.314", "4786.738", "4678.451", "4712.311", "4619.877", "4563.772", "4634.090", "4608.773", "4652.061", "4639.863", "4601.395", "4551.688", "4600.103", "4617.989", "4629.165", "4651.236", "4634.314", "4574.153", "4623.047", "4529.319", "4573.425", "4581.646", "4619.686", "4578.601", "4551.628", "4496.430", "4352.778", "4265.391", "4226.346", "4292.837", "4306.522", "4174.758", "3983.812", "4156.081", "4237.696", "4265.902", "4258.746", "4255.295", "4276.517", "4251.306", "4174.574", "4148.466", "4134.144", "4254.099", "4222.597", "4276.158", "4263.841", "4209.100", "4230.767", "4100.070", "4179.973", "4139.737", "4191.568", "4188.747", "4166.384", "4134.902", "4070.789", "3995.830", "4013.250", "3814.913", "3784.120", "3895.536", "3921.107", "4016.241", "4010.210", "3908.815", "3877.436", "3919.868", "3976.423", "3958.740", "3988.600", "3956.538", "4005.893", "3991.907", "3999.598", "4077.600", "4053.982", "3959.154", "3983.178", "3993.045", "4001.299", "4029.018", "4091.518", "4083.177", "4089.568", "4166.085", "4179.129", "4219.812", "4175.675", "4238.994", "4189.353", "4222.311", "4278.218", "4250.061", "4309.044", "4330.433", "4325.566", "4270.623", "4343.878", "4394.772", "4444.264", "4490.517", "4421.357", "4485.011", "4466.718", "4496.030", "4489.538", "4423.970", "4443.474", "4428.781", "4354.617", "4238.234", "4212.644", "4245.976", "4225.036", "4225.673", "4170.102", "4188.678", "4107.024", "4066.975", "4101.537", "4156.911", "4148.075", "4156.291", "4109.737", "4193.543", "4191.152", "4185.679", "4177.837", "4216.959", "4180.100", "4151.074", "4181.397", "4161.082", "4082.420", "4116.240", "4107.546", "4089.521", "4075.794", "4078.840", "4043.740", "4023.613", "4015.426", "4052.280", "4054.983", "4037.684", "4093.787"}
	x, _, _, err := tools.GetZuiDaHuiChe(list)
	if err != nil {
		tools.OutPutInfo(err)
	} else {
		tools.OutPutInfo(nil, "x:", x)
	}

}

func main5() {
	tools.Logger = tools.WriteLogFile("demo", "")

	bonds := []string{"110043", "110044", "110045", "110047", "110048", "110053", "110055", "110057", "110058", "110059", "110060", "110061", "110062", "110063", "110064", "110067", "110068", "110070", "110072", "110073", "110074", "110075", "110076", "110077", "110079", "110080", "110081", "110082", "110083", "110084", "110085", "110086", "110087", "110088", "110089", "110090", "111000", "111001", "111002", "111003", "111004", "111005", "111006", "111007", "111008", "111009", "113011", "113013", "113016", "113017", "113021", "113024", "113025", "113027", "113030", "113033", "113037", "113039", "113042", "113043", "113044", "113045", "113046", "113047", "113048", "113049", "113050", "113051", "113052", "113053", "113054", "113055", "113056", "113057", "113058", "113059", "113060", "113061", "113062", "113063", "113504", "113505", "113516", "113519", "113524", "113525", "113526", "113527", "113530", "113532", "113534", "113535", "113537", "113542", "113545", "113546", "113549", "113561", "113563", "113565", "113566", "113567", "113569", "113570", "113573", "113574", "113575", "113576", "113577", "113578", "113579", "113582", "113584", "113585", "113588", "113589", "113591", "113593", "113594", "113595", "113596", "113597", "113598", "113600", "113601", "113602", "113604", "113605", "113606", "113608", "113609", "113610", "113615", "113616", "113618", "113619", "113621", "113622", "113623", "113624", "113625", "113626", "113627", "113628", "113629", "113631", "113632", "113633", "113634", "113636", "113637", "113638", "113639", "113640", "113641", "113643", "113644", "113646", "113647", "113648", "113649", "113650", "113651", "113652", "113653", "113654", "113655", "113656", "113657", "113658", "113659", "118000", "118003", "118004", "118005", "118006", "118007", "118008", "118009", "118010", "118011", "118012", "118013", "118014", "118015", "118016", "118017", "118018", "118019", "118020", "118021", "118022", "118023", "118024", "118025", "118026", "123002", "123004", "123010", "123011", "123012", "123013", "123014", "123015", "123018", "123022", "123025", "123031", "123034", "123035", "123038", "123039", "123044", "123046", "123048", "123049", "123050", "123052", "123054", "123056", "123057", "123059", "123060", "123061", "123063", "123064", "123065", "123067", "123071", "123072", "123075", "123076", "123077", "123078", "123080", "123082", "123083", "123085", "123087", "123088", "123090", "123091", "123092", "123093", "123096", "123098", "123099", "123100", "123101", "123103", "123104", "123105", "123106", "123107", "123108", "123109", "123112", "123113", "123114", "123115", "123116", "123117", "123118", "123119", "123120", "123121", "123122", "123124", "123125", "123126", "123127", "123128", "123129", "123130", "123131", "123132", "123133", "123134", "123135", "123136", "123138", "123140", "123141", "123142", "123143", "123144", "123145", "123146", "123147", "123148", "123149", "123150", "123151", "123152", "123153", "123154", "123155", "123156", "123157", "123158", "123159", "123160", "123161", "123162", "123163", "123164", "123165", "123166", "127004", "127005", "127006", "127007", "127012", "127014", "127015", "127016", "127017", "127018", "127019", "127020", "127022", "127024", "127025", "127026", "127027", "127028", "127029", "127030", "127031", "127032", "127033", "127034", "127035", "127036", "127037", "127038", "127039", "127040", "127041", "127042", "127043", "127044", "127045", "127046", "127047", "127049", "127050", "127051", "127052", "127053", "127054", "127055", "127056", "127057", "127058", "127059", "127060", "127061", "127062", "127063", "127064", "127065", "127066", "127067", "127068", "127069", "127070", "127071", "127072", "127073", "127074", "127075", "127076", "128014", "128017", "128021", "128022", "128023", "128025", "128026", "128029", "128030", "128033", "128034", "128035", "128036", "128037", "128039", "128040", "128041", "128042", "128044", "128048", "128049", "128053", "128056", "128062", "128063", "128066", "128070", "128071", "128072", "128074", "128075", "128076", "128078", "128079", "128081", "128082", "128083", "128085", "128087", "128090", "128091", "128095", "128097", "128100", "128101", "128105", "128106", "128108", "128109", "128111", "128114", "128116", "128117", "128118", "128119", "128120", "128121", "128122", "128123", "128124", "128125", "128127", "128128", "128129", "128130", "128131", "128132", "128133", "128134", "128135", "128136", "128137", "128138", "128140", "128141", "128142", "128143", "128144", "128145"}
	//bonds := []string{"111001", "111002", "111003", "111004", "111005", "111006", "111007", "111008", "111009", "113011", "113013", "113016", "113017", "113021", "113024", "113025", "113027", "113030", "113033", "113037", "113039", "113042", "113043", "113044", "113045", "113046", "113047", "113048", "113049", "113050", "113051", "113052", "113053", "113054", "113055", "113056", "113057", "113058", "113059", "113060", "113061", "113062", "113063", "113504", "113505", "113516", "113519", "113524", "113525", "113526", "113527", "113530", "113532", "113534", "113535", "113537", "113542", "113545", "113546", "113549", "113561", "113563", "113565", "113566", "113567", "113569", "113570", "113573", "113574", "113575", "113576", "113577", "113578", "113579", "113582", "113584", "113585", "113588", "113589", "113591", "113593", "113594", "113595", "113596", "113597", "113598", "113600", "113601", "113602", "113604", "113605", "113606", "113608", "113609", "113610", "113615", "113616", "113618", "113619", "113621", "113622", "113623", "113624", "113625", "113626", "113627", "113628", "113629", "113631", "113632", "113633", "113634", "113636", "113637", "113638", "113639", "113640", "113641", "113643", "113644", "113646", "113647", "113648", "113649", "113650", "113651", "113652", "113653", "113654", "113655", "113656", "113657", "113658", "113659", "118000", "118003", "118004", "118005", "118006", "118007", "118008", "118009", "118010", "118011", "118012", "118013", "118014", "118015", "118016", "118017", "118018", "118019", "118020", "118021", "118022", "118023", "118024", "118025", "118026", "123002", "123004", "123010", "123011", "123012", "123013", "123014", "123015", "123018", "123022", "123025", "123031", "123034", "123035", "123038", "123039", "123044", "123046", "123048", "123049", "123050", "123052", "123054", "123056", "123057", "123059", "123060", "123061", "123063", "123064", "123065", "123067", "123071", "123072", "123075", "123076", "123077", "123078", "123080", "123082", "123083", "123085", "123087", "123088", "123090", "123091", "123092", "123093", "123096", "123098", "123099", "123100", "123101", "123103", "123104", "123105", "123106", "123107", "123108", "123109", "123112", "123113", "123114", "123115", "123116", "123117", "123118", "123119", "123120", "123121", "123122", "123124", "123125", "123126", "123127", "123128", "123129", "123130", "123131", "123132", "123133", "123134", "123135", "123136", "123138", "123140", "123141", "123142", "123143", "123144", "123145", "123146", "123147", "123148", "123149", "123150", "123151", "123152", "123153", "123154", "123155", "123156", "123157", "123158", "123159", "123160", "123161", "123162", "123163", "123164", "123165", "123166", "127004", "127005", "127006", "127007", "127012", "127014", "127015", "127016", "127017", "127018", "127019", "127020", "127022", "127024", "127025", "127026", "127027", "127028", "127029", "127030", "127031", "127032", "127033", "127034", "127035", "127036", "127037", "127038", "127039", "127040", "127041", "127042", "127043", "127044", "127045", "127046", "127047", "127049", "127050", "127051", "127052", "127053", "127054", "127055", "127056", "127057", "127058", "127059", "127060", "127061", "127062", "127063", "127064", "127065", "127066", "127067", "127068", "127069", "127070", "127071", "127072", "127073", "127074", "127075", "127076", "128014", "128017", "128021", "128022", "128023", "128025", "128026", "128029", "128030", "128033", "128034", "128035", "128036", "128037", "128039", "128040", "128041", "128042", "128044", "128048", "128049", "128053", "128056", "128062", "128063", "128066", "128070", "128071", "128072", "128074", "128075", "128076", "128078", "128079", "128081", "128082", "128083", "128085", "128087", "128090", "128091", "128095", "128097", "128100", "128101", "128105", "128106", "128108", "128109", "128111", "128114", "128116", "128117", "128118", "128119", "128120", "128121", "128122", "128123", "128124", "128125", "128127", "128128", "128129", "128130", "128131", "128132", "128133", "128134", "128135", "128136", "128137", "128138", "128140", "128141", "128142", "128143", "128144", "128145"}
	//bonds:= []string{"110043"}
	tools.OutPutInfo(nil, "bonds:", bonds)

	allocCtx, _ := chromedp.NewExecAllocator(context.Background(),
		chromedp.ExecPath(`C:\Program Files\Google\Chrome\Application\chrome.exe`),
		chromedp.Flag("headless", true),
		chromedp.Flag("blink-settings", "imagesEnabled=true"),
		chromedp.WindowSize(1000, 2000),
		chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
	)

	//create context
	var ctx context.Context
	var cancel context.CancelFunc
	//defer cancel()

	ctx, cancel = chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
	tools.OutPutInfo(nil, "启动浏览器完成")

	db, err := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	if err != nil {
		tools.OutPutInfo(err)
		return
	}

	var noTickData []string
	market := ""
	for _, v := range bonds {
		createSql := `CREATE TABLE IF NOT EXISTS tick_bond_` + v + ` LIKE fund.tick_template;`
		tools.OutPutInfo(nil, createSql)
		_, err = db.Exec(createSql)
		if err != nil {
			tools.OutPutInfo(err, "tick建表[异常]")
			return
		}

		if v[:2] == "11" {
			market = "1"
		} else {
			market = "2"
		}
		_, err := tools.ChromedpCheckNavigate(ctx, `http://quote.eastmoney.com/f1.html?code=`+v+`&market=`+market)
		if err != nil {
			tools.OutPutInfo(err, "tick数据页面[异常]")
			return
		}
		tools.Sleep(1000)

		//获取页码
		dataPage, err := tools.ChromedpCheckText(ctx,
			`#app > div > div > div.stockf1 > div.f1page2 > div > span:nth-child(5)`,
			3,
		)
		if err != nil {
			tools.OutPutInfo(err, v)
			return
		}
		tools.OutPutInfo(nil, v, "dataPage:", dataPage)

		dataPage = strings.ReplaceAll(dataPage, "页", "")
		dataPageSlice := strings.Split(dataPage, `/`)
		tools.OutPutInfo(nil, v, "dataPageSlice[1]:", dataPageSlice[1])

		pageInt, err := strconv.Atoi(dataPageSlice[1])
		if err != nil {
			tools.OutPutInfo(err, v)
			return
		}

		if pageInt < 2 {
			tools.OutPutInfo(nil, v, "页数过小[异常]")
			return
		}

		//循环页码
		//pageInt = 1//linshi
		var insertDataMapSlice []map[string]string
		for i := 1; i <= pageInt; i++ {
			//输入页码
			_, err = tools.ChromedpCheckSetValue(ctx, `form > input.gotoinput`, strconv.Itoa(i), 3)
			if err != nil {
				tools.OutPutInfo(err, v)
				return
			}
			//点GO
			_, err = tools.ChromedpCheckClick(ctx, `form > input[type=submit]:nth-child(2)`, 3, `http://huaxiang.eastmoney.com/CommonRecommend.png`, 5000)
			if err != nil {
				tools.OutPutInfo(err, v)
				return
			}
			//获取4个table的html
			tables, err := tools.ChromedpCheckInnerHTML(ctx, `#app > div > div > div.stockf1 > div.f1content.self_clearfix`, 3)
			if err != nil {
				tools.OutPutInfo(err, v)
				return
			}
			tools.OutPutInfo(nil, v, "tables:", tables)

			tablesDoc, err := tools.HtmlToDoc(tables)
			if err != nil {
				tools.OutPutInfo(err, v)
				return
			}
			//dataMapSlice2 = append(dataMapSlice2, map[string]string{
			//	"gonggao": s.Find("div.grid-col-9 > a").Text(),
			//	"date":    s.Find("div.grid-col-3").Text(),
			//}
			tablesDoc.Find(`tbody>tr`).Each(func(i int, s *goquery.Selection) {
				class, exist := s.Find(`td:nth-child(3)>span`).Attr("class")
				if !exist {
					tools.OutPutInfo(nil, "class:", i, class)
					return
				}

				var direction string
				if class == "price_up" || class == "price_up2" {
					direction = "1"
				} else if class == "price_down" || class == "price_down2" {
					direction = "2"
				} else if class == "price_draw" {
					direction = "3"
				} else {
					tools.OutPutInfo(nil, i, "class值[异常]")
					return
				}

				insertDataMapSlice = append(insertDataMapSlice, map[string]string{
					"code":      v,
					"date":      tools.GetCurrentStringDate(),
					"time":      strings.ReplaceAll(s.Find(`td:nth-child(1)`).Text(), ":", ""),
					"price":     s.Find(`td:nth-child(2)>span:nth-child(1)`).Text(),
					"count":     s.Find(`td:nth-child(3)>span`).Text(),
					"direction": direction,
				})
			})
		}
		tools.OutPutInfo(nil, v, "insertDataMapSlice:", insertDataMapSlice)

		insertCnt, err, _ := tools.InsertAllOneConnect(db, "tick_bond_"+v, insertDataMapSlice, "REPLACE")
		if err != nil {
			tools.OutPutInfo(err, v)
			return
		}
		tools.OutPutInfo(nil, v, "insertCnt:", insertCnt)

	}

	tools.OutPutInfo(nil, "noTickData:", noTickData)
	cancel()
}

func main6() {
	url := "https://www.ninwin.cn/index.php?m=cb&a=past"
	method := "GET"

	client := &http.Client{}
	req, err := http.NewRequest(method, url, nil)

	if err != nil {
		fmt.Println(err)
		return
	}
	req.Header.Add("Cookie", "P0s_cbQuestion=1; P0s_lastvisit=5265%091670768255%09%2Findex.php%3Fm%3Dcb%26a%3Dpast; P0s_visitor=MoXSwyN2CKi%2B%2BEkIBnHb0RdOgVBHfIBbN28gaLaMHpy5vTbKtiRdDQODv%2BQ%3D; csrf_token=ca1a621ec50d3e3c")

	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(ConvertTostring(string(body), "gbk", "utf-8"))

}

func ConvertTostring(src string, srcCode string, tagCode string) string {
	srcCoder := mahonia.NewDecoder(srcCode)
	srcResult := srcCoder.ConvertString(src)
	tagCoder := mahonia.NewDecoder(tagCode)
	_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
	result := string(cdata)
	return result
}

func main7() {
	tools.Logger = tools.WriteLogFile("demo", "")

	db, err1 := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	defer db.Close()
	if err1 != nil {
		tools.OutPutInfo(err1, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}

	//1.查找所有的tick_bond_* 和tick_stock_*
	b, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`SELECT TABLE_NAME FROM information_schema.TABLES 
WHERE TABLE_NAME like "tick_bond\_%" AND TABLE_NAME <>"tick_bond_template";`,
		3)
	if err != nil {
		tools.OutPutInfo(err, "查找数据库全部可转债表列表[程序异常]")
		//return nil, errors.New("查找数据库全部可转债表列表[程序异常]" + err.Error())
	}
	tools.OutPutInfo(nil, "b:", b)

	//2.循环
	for _, v := range b {
		//2.1 读取每个表2023-02-01的数据
		data, err := tools.MySqlQueryOneConnect(db, "", "", "", "", "",
			"select * from "+v["TABLE_NAME"]+" where date = '20230201'")
		if err != nil {
			tools.OutPutInfo(err)
			return
		}
		//tools.OutPutInfo2(nil, "", "data:", data)

		var slice []string
		for _, vv := range data {
			slice = append(slice, vv["code"]+","+vv["date"]+","+vv["time"]+","+vv["price"]+","+vv["count"]+","+vv["direction"])
		}
		//2.2 写入csv文件
		tools.WriteLog(strings.Join([]string{"code", "date", "time", "price", "count", "direction"}, ",")+"\n", "./tick/"+v["TABLE_NAME"]+".csv")
		tools.WriteLog(strings.Join(slice, "\n"), "./tick/"+v["TABLE_NAME"]+".csv")
	}

	s, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`SELECT TABLE_NAME FROM information_schema.TABLES 
WHERE TABLE_NAME like "tick_stock\_%" AND TABLE_NAME <>"tick_stock_template";`,
		3)
	if err != nil {
		tools.OutPutInfo(err, "查找数据库全部可转债表列表[程序异常]")
		//return nil, errors.New("查找数据库全部可转债表列表[程序异常]" + err.Error())
	}
	tools.OutPutInfo(nil, "s:", s)

	for _, v := range s {
		//2.1 读取每个表2023-02-01的数据
		data, err := tools.MySqlQueryOneConnect(db, "", "", "", "", "",
			"select * from "+v["TABLE_NAME"]+" where date = '20230201'")
		if err != nil {
			tools.OutPutInfo(err)
			return
		}
		//tools.OutPutInfo2(nil,"","data:",data)
		var slice []string
		for _, vv := range data {
			slice = append(slice, vv["code"]+","+vv["date"]+","+vv["time"]+","+vv["price"]+","+vv["count"]+","+vv["direction"])
		}
		//2.2 写入csv文件
		tools.WriteLog(strings.Join([]string{"code", "date", "time", "price", "count", "direction"}, ",")+"\n", "./tick/"+v["TABLE_NAME"]+".csv")
		tools.WriteLog(strings.Join(slice, "\n"), "./tick/"+v["TABLE_NAME"]+".csv")
	}

}

func main8() {
	tools.Logger = tools.WriteLogFile("demo", "")

	//tools.OutPutInfo2(nil,"",path.Base(`C:\\src\\go\\gitee.com\\weiwei\\study-go-lang\\demo\\tick/tick_stock_688779.csv`))
	//return

	db, err1 := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	defer db.Close()
	if err1 != nil {
		tools.OutPutInfo(err1, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}

	//1.查找所有的csv文件
	files, err := tools.ReadAll(`C:\src\go\gitee.com\weiwei\study-go-lang\demo\tick`)
	if err != nil {
		tools.OutPutInfo2(err, "")
		return
	}
	tools.OutPutInfo2(nil, "", "files:", files)
	//2.循环
	for _, v := range files {
		data, err := tools.GetCsvData(v)
		if err != nil {
			tools.OutPutInfo2(err, "")
			return
		}
		cnt, err, _ := tools.InsertAllOneConnect(db, strings.ReplaceAll(path.Base(v), ".csv", ""), data, "")
		if err != nil {
			tools.OutPutInfo2(err, "")
			return
		} else {
			tools.OutPutInfo2(nil, "", strings.ReplaceAll(path.Base(v), ".csv", ""), cnt)
		}
	}
	//2.1 读取当前循环的csv文件内容
	//2.2 写入对应的表中

}

func main9() {
	tools.Logger = tools.WriteLogFile("demo", "")

	db, err1 := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	defer db.Close()
	if err1 != nil {
		tools.OutPutInfo(err1, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}

	data, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		"select * from etf_510310 where zuigao = shoupan", 3)
	if err != nil {
		tools.OutPutInfo2(err, "")
		return
	}
	tools.OutPutInfo2(nil, "", "data:", data)

	tools.WriteLog(strings.Join([]string{"代码", "名称", "锤头线日期", "前第10天", "前第9天", "前第8天", "前第7天", "前第6天", "前第5天", "前第4天", "前第3天", "前第2天", "前第1天",
		"锤头线当日", "后第1天", "后第2天", "后第3天", "后第4天", "后第5天", "后第6天", "后第7天", "后第8天", "后第9天", "后第10天"}, ",")+"\n", "tuitouxian.csv")
	var sliceAll []string
	for _, v := range data {
		d, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
			`
select * from (
(select * from etf_510310 where date <= '`+v["date"]+`' order by date desc limit 11)
		UNION
	(select * from etf_510310 where date > '`+v["date"]+`' order by date asc limit 10)	
	) t order by date
`, 3)
		if err != nil {
			tools.OutPutInfo2(err, "")
			return
		}
		tools.OutPutInfo2(nil, "", "d:", d)

		var slice []string
		slice = append(slice, v["code"], v["name"], v["date"])
		for _, vv := range d {
			slice = append(slice, vv["shoupan"])
		}
		sliceAll = append(sliceAll, strings.Join(slice, ","))
	}
	tools.WriteLog(strings.Join(sliceAll, "\n"), "tuitouxian.csv")
}

func GetData() ([][]string, error) {

	db, err1 := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	defer db.Close()
	if err1 != nil {
		tools.OutPutInfo(err1, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}

	currentDate, _ := tools.GetCurrentStringDateFormat("2006-01-02")
	//currentDate = "2023-03-03"

	os.RemoveAll(`./锤头线`)
	tools.Sleep(1000)
	os.MkdirAll(`./锤头线`, 0777)

	b, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`SELECT TABLE_NAME FROM information_schema.TABLES 
WHERE TABLE_NAME like "stock\_%" || TABLE_NAME LIKE "etf\_%" || (TABLE_NAME LIKE "bond\_%" && TABLE_NAME != 'bond_000000') order by TABLE_NAME`, 3)
	if err != nil {
		tools.OutPutInfo(err, "查找数据库全部etf表列表[程序异常]")
		panic(1)
	}
	tools.OutPutInfo(nil, "b:", b)
	var sliceAll [][]string
	for _, t := range b {
		if strings.Contains(t["TABLE_NAME"], "stock_8") ||
			strings.Contains(t["TABLE_NAME"], "stock_4") ||
			strings.Contains(t["TABLE_NAME"], "stock_68") {
			continue
		}
		data, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
			`select * from `+t["TABLE_NAME"]+` 
where zuigao = shoupan and zuidi < kaipan and date = '`+currentDate+`'
and (CONVERT(kaipan,DECIMAL(32,4)) - CONVERT(zuidi,DECIMAL(32,4)))/(CONVERT(zuigao,DECIMAL(32,4)) - CONVERT(kaipan,DECIMAL(32,4))) >=0.8
 `, 3)
		if err != nil {
			tools.OutPutInfo2(err, "", t["TABLE_NAME"])
			panic(1)
			return nil, err
		}
		tools.OutPutInfo2(nil, "", "data:", data)

		//tools.WriteLog(strings.Join([]string{"代码", "名称", "锤头线日期", "前第10天", "前第9天", "前第8天", "前第7天", "前第6天", "前第5天", "前第4天", "前第3天", "前第2天", "前第1天",
		//	"锤头线当日", "后第1天", "后第2天", "后第3天", "后第4天", "后第5天", "后第6天", "后第7天", "后第8天", "后第9天", "后第10天"}, ",")+"\n", "tuitouxian.csv")

		for _, v := range data {
			sql := `
select * from (
(select * from ` + t["TABLE_NAME"] + ` where date <= '` + v["date"] + `' order by date desc limit 11)
		UNION
	(select * from ` + t["TABLE_NAME"] + ` where date > '` + v["date"] + `' order by date asc limit 10)	
	) t order by date
`
			d, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "", sql, 3)
			if err != nil {
				tools.OutPutInfo2(err, "sql:", sql)
				return nil, err
			}
			tools.OutPutInfo2(nil, "", "d:", d)

			var slice []string
			slice = append(slice, v["code"], v["name"], v["date"])
			for _, vv := range d {
				slice = append(slice, strings.Join([]string{vv["kaipan"], vv["shoupan"], vv["zuigao"], vv["zuidi"], vv["chengjiaoliang"]}, ","))
			}

			before10, err := decimal.NewFromString(d[0]["shoupan"])
			if err != nil {
				tools.OutPutInfo(err, v["code"], v["name"], v["date"], d[0]["shoupan"], "sql:", sql)
			}
			if before10.Equal(decimal.Zero) {
				tools.OutPutInfo2(nil, v["code"], v["name"], v["date"], "before10为0")
				return nil, err
			}
			chuitou, err := decimal.NewFromString(d[10]["shoupan"])
			if chuitou.DivRound(before10, 4).
				Sub(decimal.NewFromInt(1)).
				Mul(decimal.NewFromInt(-100)).
				GreaterThan(decimal.NewFromInt(1)) {
				sliceAll = append(sliceAll, slice)
			}

		}
	}

	return sliceAll, nil
}

var detailLogFlag = false

func GetData2() ([][]string, error) {

	db, err1 := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	defer db.Close()
	if err1 != nil {
		tools.OutPutInfo(err1, "数据库连接[程序异常]")
		//SendMsg("0003:" + err1.Error())
		os.Exit(1)
	} else {
		tools.OutPutInfo(nil, "数据库连接[正常]")
	}

	bonds, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
		`
select bond_code,bond_name,stock_code,stock_name,shangshiri,hezhunriqi,faxingriqi
from bonds
where shangshiri >= '2018-01-01' and faxingriqi <= '2022-09-30' and hezhunriqi != '-'
order by hezhunriqi desc
`, 3)
	if err != nil {
		tools.OutPutInfo2(err, "")
		panic(1)
	}
	if detailLogFlag {
		tools.OutPutInfo2(nil, "", "bonds:", bonds)
	}
	var sliceAll [][]string
	for _, b := range bonds {
		sql := `
select * from stock_` + b["stock_code"] + `
where date >= '` + b["hezhunriqi"] + `' and date <= '` + b["faxingriqi"] + `'
order by date asc
`
		data, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
			sql, 3)
		if err != nil {
			tools.OutPutInfo2(err, "")
			panic(1)
			return nil, err
		}
		tools.OutPutInfo2(nil, "", "data:", data)

		//tools.WriteLog(strings.Join([]string{"代码", "名称", "锤头线日期", "前第10天", "前第9天", "前第8天", "前第7天", "前第6天", "前第5天", "前第4天", "前第3天", "前第2天", "前第1天",
		//	"锤头线当日", "后第1天", "后第2天", "后第3天", "后第4天", "后第5天", "后第6天", "后第7天", "后第8天", "后第9天", "后第10天"}, ",")+"\n", "tuitouxian.csv")
		var slice []string
		slice = append(slice, b["hezhunriqi"], b["stock_code"], b["stock_name"])
		for _, v := range data {
			//			d, err := tools.MySqlQueryOneConnectTimes(db, "", "", "", "", "",
			//				`
			//select * from (
			//(select * from stock_`+b["stock_code"]+` where date <= '`+v["date"]+`' order by date desc limit 11)
			//		UNION
			//	(select * from stock_`+b["stock_code"]+` where date > '`+v["date"]+`' order by date asc limit 10)
			//	) t order by date
			//`, 3)
			//			if err != nil {
			//				tools.OutPutInfo2(err, "")
			//				return nil, err
			//			}
			//			tools.OutPutInfo2(nil, "", "d:", d)
			slice = append(slice, strings.Join([]string{v["date"], v["kaipan"], v["shoupan"], v["zuigao"], v["zuidi"], v["chengjiaoliang"]}, ","))

			//for _, vv := range d {
			//	slice = append(slice, strings.Join([]string{vv["kaipan"], vv["shoupan"], vv["zuigao"], vv["zuidi"], vv["chengjiaoliang"]}, ","))
			//}

			//before10, err := decimal.NewFromString(d[0]["shoupan"])
			//chuitou, err := decimal.NewFromString(d[10]["shoupan"])
			//if chuitou.DivRound(before10, 4).
			//	Sub(decimal.NewFromInt(1)).
			//	Mul(decimal.NewFromInt(-100)).
			//	GreaterThan(decimal.NewFromInt(1)) {
			//	sliceAll = append(sliceAll, slice)
			//}

		}
		sliceAll = append(sliceAll, slice)

	}

	return sliceAll, nil
}

// 转债核准策略 生成k线图 使用go-charts
func main12() {
	tools.Logger = tools.WriteLogFile("demo", "")

	data, err := GetData2() //用于生成核准后正股走势k线图的数据
	if err != nil {
		tools.OutPutInfo2(err, "")
		return
	}
	tools.OutPutInfo2(nil, "", "data:", data)
	//return
	for _, stock := range data { //一个v代表一个正股
		//volumeSum := decimal.NewFromInt(0)
		filename := stock[0] + "_" + stock[1] + strings.ReplaceAll(stock[2], "*", "x") + ".html"
		//var i = 10
		//var i2 = 1
		for k, datePrice := range stock {
			//k==0 hezhunriqi
			//k==1 code
			//k==2 name
			//k>=3 data,price
			if k >= 3 {
				var flo [4]float32
				var date string
				for kkk, vvv := range strings.Split(datePrice, ",") {
					if kkk == 0 {
						date = vvv
						continue
					}
					if kkk == 5 {
						break
					}
					tmp, err := strconv.ParseFloat(vvv, 64)
					if err != nil {
						tools.OutPutInfo2(err, "")
						return
					}
					flo[kkk-1] = float32(tmp)
				}
				//tmp3:=strings.Split(vv, ",")[4]//成交量
				tmp2, err := decimal.NewFromString(strings.Split(datePrice, ",")[5]) //成交量
				if err != nil {
					tools.OutPutInfo2(err, "")
					return
				}
				//if i >= 1 {
				//	kd = append(kd, klineData{date: "前第" + strconv.Itoa(i) + "天", data: flo})
				//	bd = append(bd, barData{date: "前第" + strconv.Itoa(i) + "天", data: tmp2})
				//	volumeSum = volumeSum.Add(tmp2) //成交量累加
				//	i--
				//} else if i == 0 {
				//	kd = append(kd, klineData{date: "锤头线当天", data: flo})
				//	bd = append(bd, barData{date: "锤头线当天", data: tmp2, avg: volumeSum.DivRound(decimal.NewFromInt(10), 2)})
				//	i--
				//} else {
				//	kd = append(kd, klineData{date: "后第" + strconv.Itoa(i2) + "天", data: flo})
				//	bd = append(bd, barData{date: "后第" + strconv.Itoa(i2) + "天", data: tmp2})
				//	i2++
				//}
				kd = append(kd, klineData{date: date, data: flo})
				bd = append(bd, barData{date: date, data: tmp2})
			}
		}
		for _, v1 := range kd {
			tools.OutPutInfo2(nil, "", "kd:", v1.date, v1.data)
		}
		kline := KlineExamples{}
		kline.Examples(filename)
		kd = nil
		bd = nil
	}

}

// etf stock bond 锤头线 画前后k线图  使用go-charts
func main16() {
	//main16
	tools.Logger = tools.WriteLogFile("demo", "")

	data, err := GetData()
	if err != nil {
		tools.OutPutInfo2(err, "")
		return
	}
	tools.OutPutInfo2(nil, "", "data:", data)

	for _, v := range data { //一个v代表一个锤头线出现的数据
		volumeSum := decimal.NewFromInt(0)
		filename := v[0] + strings.ReplaceAll(v[1], "*", "x") + "_" + v[2] + ".html"
		var i = 10
		var i2 = 1
		for k, vv := range v {
			if k >= 3 {
				var flo [4]float32
				for kkk, vvv := range strings.Split(vv, ",") {
					if kkk == 4 {
						break
					}
					tmp, err := strconv.ParseFloat(vvv, 64)
					if err != nil {
						tools.OutPutInfo2(err, "")
						return
					}
					flo[kkk] = float32(tmp)
				}
				//tmp3:=strings.Split(vv, ",")[4]//成交量
				tmp2, err := decimal.NewFromString(strings.Split(vv, ",")[4]) //成交量
				if err != nil {
					tools.OutPutInfo2(err, "")
					return
				}
				if i >= 1 {
					kd = append(kd, klineData{date: "前第" + strconv.Itoa(i) + "天", data: flo})
					bd = append(bd, barData{date: "前第" + strconv.Itoa(i) + "天", data: tmp2})
					volumeSum = volumeSum.Add(tmp2) //成交量累加
					i--
				} else if i == 0 {
					kd = append(kd, klineData{date: "锤头线当天", data: flo})
					bd = append(bd, barData{date: "锤头线当天", data: tmp2, avg: volumeSum.DivRound(decimal.NewFromInt(10), 2)})
					i--
				} else {
					kd = append(kd, klineData{date: "后第" + strconv.Itoa(i2) + "天", data: flo})
					bd = append(bd, barData{date: "后第" + strconv.Itoa(i2) + "天", data: tmp2})
					i2++
				}
			}
		}
		for _, v1 := range kd {
			tools.OutPutInfo2(nil, "", "kd:", v1.date, v1.data)
		}
		kline := KlineExamples{}
		kline.Examples(filename)
		kd = nil
		bd = nil
	}

}

type klineData struct {
	date string
	data [4]float32
}
type barData struct {
	date string
	data decimal.Decimal
	avg  decimal.Decimal
}

var kd []klineData
var bd []barData

// {date: "2018/1/24", data: [4]float32{2320.26, 2320.26, 2287.3, 2362.94}},
// {date: "2018/1/25", data: [4]float32{2300, 2291.3, 2288.26, 2308.38}},
// {date: "2018/1/28", data: [4]float32{2295.35, 2346.5, 2295.35, 2346.92}},
// {date: "2018/1/29", data: [4]float32{2347.22, 2358.98, 2337.35, 2363.8}},
// {date: "2018/1/30", data: [4]float32{2360.75, 2382.48, 2347.89, 2383.76}},
// {date: "2018/1/31", data: [4]float32{2383.43, 2385.42, 2371.23, 2391.82}},
// {date: "2018/2/1", data: [4]float32{2377.41, 2419.02, 2369.57, 2421.15}},
// {date: "2018/2/4", data: [4]float32{2425.92, 2428.15, 2417.58, 2440.38}},
// {date: "2018/2/5", data: [4]float32{2411, 2433.13, 2403.3, 2437.42}},
func barBase() *charts.Bar {
	bar := charts.NewBar()
	bar.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "量",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			SplitNumber: 30,
			AxisLabel: &opts.AxisLabel{
				ShowMinLabel: true,
				ShowMaxLabel: true,
				Show:         true,
				Interval:     "0",
				Rotate:       30,
			},
		}),
	)
	x := make([]string, 0)
	y := make([]opts.BarData, 0)
	yAvg := make([]opts.BarData, 0)
	//y2 := make([]opts.BarData, 0)
	for i := 0; i < len(bd); i++ {
		x = append(x, bd[i].date)
		//y = append(y, opts.KlineData{Value: kd[i].data})
		y = append(y, opts.BarData{Value: bd[i].data})
		yAvg = append(yAvg, opts.BarData{Value: bd[i].avg})
		//if i == (len(bd)-1)/2 {
		//	yAvg = append(yAvg, opts.BarData{Value: bd[i].data})
		//}else {
		//	yAvg = append(yAvg, opts.BarData{Value: 0.0})
		//}
	}

	bar.SetXAxis(x).
		AddSeries("stackA", y).
		//AddSeries("Category C", generateBarItems()).
		SetSeriesOptions(charts.WithBarChartOpts(opts.BarChart{
			Stack: "stackA",
		}))
	bar.Overlap(lineAvg())
	return bar
}
func lineAvg() *charts.Line {
	bar := charts.NewLine()
	bar.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "平均量",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			SplitNumber: 30,
			AxisLabel: &opts.AxisLabel{
				ShowMinLabel: true,
				ShowMaxLabel: true,
				Show:         true,
				Interval:     "0",
				Rotate:       30,
			},
		}),
	)
	x := make([]string, 0)
	//y := make([]opts.BarData, 0)
	yAvg := make([]opts.LineData, 0)
	//y2 := make([]opts.BarData, 0)
	for i := 0; i < len(bd); i++ {
		x = append(x, bd[i].date)
		//y = append(y, opts.KlineData{Value: kd[i].data})
		//y = append(y, opts.BarData{Value: bd[i].data})
		yAvg = append(yAvg, opts.LineData{Value: bd[i].avg})
		//if i == (len(bd)-1)/2 {
		//	yAvg = append(yAvg, opts.BarData{Value: bd[i].data})
		//}else {
		//	yAvg = append(yAvg, opts.BarData{Value: 0.0})
		//}
	}

	bar.SetXAxis(x).
		AddSeries("avg", yAvg).
		//AddSeries("Category C", generateBarItems()).
		SetSeriesOptions(charts.WithLineChartOpts(opts.LineChart{
			Stack: "avg",
			Step:  true,
		}))
	return bar
}
func klineBase() *charts.Kline {
	kline := charts.NewKLine()

	x := make([]string, 0)
	y := make([]opts.KlineData, 0)
	for i := 0; i < len(kd); i++ {
		x = append(x, kd[i].date)
		y = append(y, opts.KlineData{Value: kd[i].data})
	}

	kline.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "价",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			SplitNumber: 30,
			AxisLabel: &opts.AxisLabel{
				ShowMinLabel: true,
				ShowMaxLabel: true,
				Show:         true,
				Interval:     "0",
				Rotate:       30,
			},
		}),
		charts.WithYAxisOpts(opts.YAxis{
			Scale: true,
		}),
		//charts.WithDataZoomOpts(opts.DataZoom{
		//	Start:      50,
		//	End:        100,
		//	XAxisIndex: []int{0},
		//}),
	)

	kline.SetXAxis(x).AddSeries("kline", y)
	return kline
}

func klineDataZoomInside() *charts.Kline {
	kline := charts.NewKLine()

	x := make([]string, 0)
	y := make([]opts.KlineData, 0)
	for i := 0; i < len(kd); i++ {
		x = append(x, kd[i].date)
		y = append(y, opts.KlineData{Value: kd[i].data})
	}

	kline.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "DataZoom(inside)",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			SplitNumber: 20,
		}),
		charts.WithYAxisOpts(opts.YAxis{
			Scale: true,
		}),
		charts.WithDataZoomOpts(opts.DataZoom{
			Type:       "inside",
			Start:      50,
			End:        100,
			XAxisIndex: []int{0},
		}),
	)

	kline.SetXAxis(x).AddSeries("kline", y)
	return kline
}

func klineDataZoomBoth() *charts.Kline {
	kline := charts.NewKLine()

	x := make([]string, 0)
	y := make([]opts.KlineData, 0)
	for i := 0; i < len(kd); i++ {
		x = append(x, kd[i].date)
		y = append(y, opts.KlineData{Value: kd[i].data})
	}

	kline.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "DataZoom(inside&slider)",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			SplitNumber: 20,
		}),
		charts.WithYAxisOpts(opts.YAxis{
			Scale: true,
		}),
		charts.WithDataZoomOpts(opts.DataZoom{
			Type:       "inside",
			Start:      50,
			End:        100,
			XAxisIndex: []int{0},
		}),
		charts.WithDataZoomOpts(opts.DataZoom{
			Type:       "slider",
			Start:      50,
			End:        100,
			XAxisIndex: []int{0},
		}),
	)

	kline.SetXAxis(x).AddSeries("kline", y)
	return kline
}

func generateBarItems() []opts.BarData {
	items := make([]opts.BarData, 0)
	for i := 0; i < len(bd); i++ {
		items = append(items, opts.BarData{Value: rand.Intn(300)})
	}
	return items
}
func klineDataZoomYAxis() *charts.Kline {
	kline := charts.NewKLine()

	x := make([]string, 0)
	y := make([]opts.KlineData, 0)
	for i := 0; i < len(kd); i++ {
		x = append(x, kd[i].date)
		y = append(y, opts.KlineData{Value: kd[i].data})
	}

	kline.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "DataZoom(yAxis)",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			SplitNumber: 20,
		}),
		charts.WithYAxisOpts(opts.YAxis{
			Scale: true,
		}),
		charts.WithDataZoomOpts(opts.DataZoom{
			Type:       "slider",
			Start:      50,
			End:        100,
			YAxisIndex: []int{0},
		}),
	)

	kline.SetXAxis(x).AddSeries("kline", y)
	return kline
}

func klineStyle() *charts.Kline {
	kline := charts.NewKLine()

	x := make([]string, 0)
	y := make([]opts.KlineData, 0)
	for i := 0; i < len(kd); i++ {
		x = append(x, kd[i].date)
		y = append(y, opts.KlineData{Value: kd[i].data})
	}

	kline.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "different style",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			SplitNumber: 20,
		}),
		charts.WithYAxisOpts(opts.YAxis{
			Scale: true,
		}),
		charts.WithDataZoomOpts(opts.DataZoom{
			Start:      50,
			End:        100,
			XAxisIndex: []int{0},
		}),
	)

	kline.SetXAxis(x).AddSeries("kline", y).
		SetSeriesOptions(
			charts.WithMarkPointNameTypeItemOpts(opts.MarkPointNameTypeItem{
				Name:     "highest value",
				Type:     "max",
				ValueDim: "highest",
			}),
			charts.WithMarkPointNameTypeItemOpts(opts.MarkPointNameTypeItem{
				Name:     "lowest value",
				Type:     "min",
				ValueDim: "lowest",
			}),
			charts.WithMarkPointStyleOpts(opts.MarkPointStyle{
				Label: &opts.Label{
					Show: true,
				},
			}),
			charts.WithItemStyleOpts(opts.ItemStyle{
				Color:        "#ec0000",
				Color0:       "#00da3c",
				BorderColor:  "#8A0000",
				BorderColor0: "#008F28",
			}),
		)
	return kline
}

type KlineExamples struct{}

func (KlineExamples) Examples(file string) {
	page := components.NewPage()
	page.AddCharts(
		klineBase(),
		barBase(),
		//klineDataZoomInside(),
		//klineDataZoomBoth(),
		//klineDataZoomYAxis(),
		//klineStyle(),
	)

	f, err := os.Create("锤头线/" + file)
	if err != nil {
		panic(err)

	}

	page.Render(io.MultiWriter(f))

}

func main11() {
	tools.Logger = tools.WriteLogFile("./demo", "")

	db, err := tools.ConMysql(`weiwei:123456@tcp(127.0.0.1:3306)/fund?charset=utf8&multiStatements=true`)
	if err != nil {
		tools.OutPutInfo(err)
		return
	}

	files, err := tools.ReadAll(`D:\360极速浏览器X下载\xbx_stock_day_data-2022-10-10\stock`)
	if err != nil {
		tools.OutPutInfo(err)
		return
	}
	tools.OutPutInfo(nil, files)

	for _, v := range files {
		code := filepath.Base(v)
		code = code[2:8]

		content, err := tools.ReadFile(v)
		if err != nil {
			tools.OutPutInfo2(err, "")
			return
		} else {
			tools.OutPutInfo(nil, code, "读文件内容完成")
		}

		gbk, err := GbkToUtf8([]byte(content))
		if err != nil {
			tools.OutPutInfo(err)
			return
		} else {
			tools.OutPutInfo(nil, code, "内容转gbk完成")
		}

		content = string(gbk)
		indx := strings.Index(content, "xbx6660")
		if indx == -1 {
			tools.OutPutInfo(nil, code, "未查找到xbx6660")
			return
		}
		//fmt.Println(indx)

		content = content[indx+8:]
		content = strings.Replace(content, "\n", "", 1)
		//fmt.Println(content)

		os.Remove("tmp.csv")
		err = tools.WriteLog(content, "tmp.csv")
		if err != nil {
			tools.OutPutInfo2(err, "", code, "写入临时csv文件异常")
			return
		} else {
			tools.OutPutInfo2(nil, "", code, "写入临时csv文件正常")
		}

		data, err := tools.GetCsvData(`tmp.csv`)
		if err != nil {
			tools.OutPutInfo2(err, "", code, "读临时csv文件异常")
			return
		} else {
			tools.OutPutInfo2(nil, "", code, "读临时csv文件正常")
		}
		//tools.OutPutInfo2(nil,"","data:",data)

		createSql := `CREATE TABLE IF NOT EXISTS stock_` + code + ` LIKE fund.stock_template;`
		tools.OutPutInfo(nil, createSql)

		_, err = db.Exec(createSql)
		if err != nil {
			tools.OutPutInfo(err, code, "stock建表[异常]")
			return
		} else {
			tools.OutPutInfo(nil, code, "创建表完成")
		}

		var dataNew []map[string]string
		for _, vv := range data {
			dataNew = append(dataNew, map[string]string{
				"code":           vv["股票代码"][2:],
				"name":           vv["股票名称"],
				"date":           vv["交易日期"],
				"kaipan":         vv["开盘价"],
				"shoupan":        vv["收盘价"],
				"zuigao":         vv["最高价"],
				"zuidi":          vv["最低价"],
				"qianshoupan":    vv["前收盘价"],
				"chengjiaoliang": vv["成交量"],
				"chengjiaoe":     vv["成交额"],
				"liutong":        vv["流通市值"],
				"zongshizhi":     vv["总市值"],
			})
		}

		cnt, err, _ := tools.InsertAllOneConnect(db, "stock_"+code, dataNew, "REPLACE")
		if err != nil {
			tools.OutPutInfo(err, code, "stock插入数据[异常]")
		}
		tools.OutPutInfo(nil, code, "创建表完成数量：", cnt)
	}

}

// GBK 转 UTF-8
func GbkToUtf8(s []byte) ([]byte, error) {
	reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
	d, e := ioutil.ReadAll(reader)
	if e != nil {
		return nil, e
	}
	return d, nil
}

// UTF-8 转 GBK
func Utf8ToGbk(s []byte) ([]byte, error) {
	reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder())
	d, e := ioutil.ReadAll(reader)
	if e != nil {
		return nil, e
	}
	return d, nil
}

func OpenBrowser(xueQiuUrl []string) error {
	chromePath := ``
	allocCtx, _ := chromedp.NewExecAllocator(context.Background(),
		chromedp.ExecPath(chromePath),
		chromedp.Flag("headless", false),
		chromedp.Flag("blink-settings", "imagesEnabled=true"),
		chromedp.WindowSize(1000, 2000),
		chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
	)
	//create context
	ctx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
	tools.OutPutInfo(nil, "启动浏览器完成")

	for _, url := range xueQiuUrl {
		ctx, cancel = chromedp.NewContext(ctx)
		_, err := tools.ChromedpCheckNavigate(ctx, url)
		if err != nil {
			tools.OutPutInfo(err, "打开交易系统登录页面[异常]")
			return err
		}

		tools.OutPutInfo(nil, "启动浏览器完成")
	}

	defer cancel()

	return nil
}

type DATA_BLOB struct {
	cbData uint32
	pbData *byte
}

func NewBlob(d []byte) *DATA_BLOB {
	if len(d) == 0 {
		return &DATA_BLOB{}
	}
	b := &DATA_BLOB{
		pbData: &d[0],
		cbData: uint32(len(d)),
	}

	return b
}
func (b *DATA_BLOB) ToByteArray() []byte {
	d := make([]byte, b.cbData)
	copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
	return d
}

func dpapi_decrypt(encrypted []byte) ([]byte, error) {
	dllcrypt32 := syscall.NewLazyDLL("Crypt32.dll")
	dllkernel32 := syscall.NewLazyDLL("Kernel32.dll")

	procDecryptData := dllcrypt32.NewProc("CryptUnprotectData")
	procLocalFree := dllkernel32.NewProc("LocalFree")
	var outblob DATA_BLOB
	r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(encrypted))), 0, 0, 0, 0, 0x1, uintptr(unsafe.Pointer(&outblob)))
	if r == 0 {
		return nil, err
	}
	defer procLocalFree.Call(uintptr(unsafe.Pointer(outblob.pbData)))
	return outblob.ToByteArray(), err
}

func aesGCMDecrypt(data []byte, key []byte, iv []byte) []byte {
	block, _ := aes.NewCipher(key)
	aesGcm, _ := cipher.NewGCM(block)
	plaintext, _ := aesGcm.Open(nil, iv, data, nil)
	return plaintext
}

func aes_decrypt(encrypted_txt string) []byte {
	//key_file, _ := os.OpenFile(os.Getenv("LOCALAPPDATA")+"\\Microsoft\\Edge\\User Data\\Local State", os.O_RDONLY, os.ModePerm)
	key_file, _ := os.OpenFile(os.Getenv("LOCALAPPDATA")+"\\Google\\Chrome\\User Data\\Local State", os.O_RDONLY, os.ModePerm)
	defer key_file.Close()
	key_data, _ := ioutil.ReadAll(key_file)

	dynamic := make(map[string]interface{})
	json.Unmarshal([]byte(string(key_data)), &dynamic)
	encrypted_key, _ := base64.StdEncoding.DecodeString(dynamic["os_crypt"].(map[string]interface{})["encrypted_key"].(string))
	encrypted_key = encrypted_key[5:]      //去掉DPAPI后的加密key
	key, _ := dpapi_decrypt(encrypted_key) //解密后的key
	nonce := encrypted_txt[3:15]           //AES随机12位vi
	decryptor := aesGCMDecrypt([]byte(encrypted_txt[15:]), key, []byte(nonce))
	return decryptor
}

/*前缀处理*/
func chrome_decrypt(encrypted_txt string) []byte {
	var decrypted_txt []byte
	if encrypted_txt[:3] == "v10" {
		decrypted_txt = aes_decrypt(encrypted_txt)
	}
	if encrypted_txt[:4] == "DPAP" {
		decrypted_txt, _ = dpapi_decrypt([]byte(encrypted_txt))
	}
	return decrypted_txt
}

func get_cookies_from_chrome(domain string) []map[string]string {
	query := `SELECT name, encrypted_value as value,host_key as domain, path FROM cookies where host_key like ` + `"%` + domain + `%"`
	fmt.Println(query)
	var file string
	if _, err := os.Stat(os.Getenv("LOCALAPPDATA") + "\\Microsoft\\Edge\\User Data\\Default\\Network\\Cookies"); err == nil {
		file = os.Getenv("LOCALAPPDATA") + "\\Microsoft\\Edge\\User Data\\Default\\Network\\Cookies"
	} else if _, err := os.Stat(os.Getenv("LOCALAPPDATA") + "\\Microsoft\\Edge\\User Data\\Profile 3\\Network\\Cookies"); err == nil {
		file = os.Getenv("LOCALAPPDATA") + "\\Microsoft\\Edge\\User Data\\Profile 3\\Network\\Cookies"
	}
	file = `C:\Users\Admin\AppData\Local\Google\Chrome\User Data\Default\Network\Cookies`

	fmt.Println(file)
	db2, err := sql.Open("sqlite3", file)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer db2.Close()
	rows, _ := db2.Query(query)
	defer rows.Close()
	var cookies []map[string]string
	for rows.Next() {
		var name, value, domain, path string
		rows.Scan(&name, &value, &domain, &path)
		if name != "" && value != "" {
			cc_data_tmp := make(map[string]string)
			cc_data_tmp["name"] = name
			cc_data_tmp["value"] = string(chrome_decrypt(value))
			cc_data_tmp["doamin"] = domain
			cc_data_tmp["path"] = path
			cookies = append(cookies, cc_data_tmp)
		}
	}

	return cookies
}
